/*
 * Created by SharpDevelop.
 * User: Edward Wilde (http://blogs.charteris.com/edwardw)
 * Date: 02/07/2007
 * Time: 18:52
 * 
 */

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Globalization;
using System.IO;
using System.Threading;
using System.Windows.Forms;
using NUnit.Framework;
using Wax;

namespace Wax.Runner
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    public partial class MainForm : Form
    {
        #region Private fields

        /// <summary>
        /// Object that manages the loading and execution of tests
        /// </summary>
        private readonly TestRunner testRunner;

        /// <summary>
        /// Grid that displays tests to be executed
        /// </summary>
        private TestGrid testGrid;

        /// <summary>
        /// Usercontrol that displays a property sheet and a results sheet
        /// </summary>
        private ResultsPanel resultsPanel;

        #endregion

        #region Constructors

        public MainForm()
        {
            this.testRunner = new TestRunner();
            
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            InitializeControls();
        }

        #endregion

        #region Public instance methods

        /// <summary>
        /// Updates the status.
        /// </summary>
        /// <param name="message">The message.</param>
        public void UpdateStatus(string message)
        {
            if (string.IsNullOrEmpty(message))
            {
                throw new ArgumentNullException("message");
            }

            this.statusLabel.Text = message;
        }

        #endregion

        #region Private instance methods

        #region Form initialization

        /// <summary>
        /// Initializes the controls.
        /// </summary>
        private void InitializeControls()
        {
            // Initialize the test runner component
            this.testRunner.Progress += new EventHandler<TestProgressEventArgs>(TestRunnerProgress);
            this.testRunner.ExecutionStarted += new EventHandler(TestRunnerExecutionStarted);
            this.testRunner.ExecutionCompleted += new EventHandler(TestRunnerExecutionCompleted);
            this.testRunner.CommandCompleted += new EventHandler<CommandCompletedEventArgs>(TestRunnerCommandCompleted);

            // Initialize the test grid
            this.testGrid = new TestGrid(this.testRunner);
            this.testGrid.Dock = DockStyle.Fill;
            this.testGrid.Visible = true;
            this.testGrid.ItemSelected += new EventHandler(TestGridItemSelected);
            this.splitContainer.Panel1.Controls.Add(this.testGrid);

            // Initialize the results panel
            this.resultsPanel = new ResultsPanel(this.testRunner);
            this.panelResults.Controls.Add(this.resultsPanel);
            this.resultsPanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
            this.resultsPanel.Location = new Point(0, 0);
            this.resultsPanel.Dock = DockStyle.Fill;
            this.resultsPanel.Visible = true;
            this.resultsPanel.Height = splitContainer.Panel2.Height - this.statusStrip1.Height;

            // Results label
            this.resultsLabel.Visible = false;

            // Intialize toolstrip
            this.playButton.Image = Resource.Play;
            this.playButton.Enabled = false;
            this.playButton.Click += new EventHandler(ToolStripOnClick);

            this.refreshButton.Image = Resource.Refresh;
            this.refreshButton.Enabled = false;
            this.refreshButton.Click += new EventHandler(ToolStripOnClick);

            // Initialize test menu itemes
            this.executeToolStripMenuItem.Image = Resource.Play;
            this.executeToolStripMenuItem.Enabled = false;

            this.refreshToolStripMenuItem.Enabled = false;
            this.refreshToolStripMenuItem.Image = Resource.Refresh;
        }

        #endregion

        #region TestRunner event handlers

        /// <summary>
        /// Handles the CommandCompleted event of the testRunner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Wax.CommandCompletedEventArgs"/> instance containing the event data.</param>
        void TestRunnerCommandCompleted(object sender, CommandCompletedEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler<CommandCompletedEventArgs>(TestRunnerCommandCompleted), new object[] { sender, e });
                return;
            }

            this.resultsLabel.Visible = true;
            this.resultsLabel.Text = string.Format(CultureInfo.InvariantCulture, Resource.ResultsLabel, e.NumberOfCompletedCommands, e.NumberOfFailedCommands);
        }


        /// <summary>
        /// Handles the ExecutionCompleted event of the testRunner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestRunnerExecutionCompleted(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(TestRunnerExecutionCompleted), new object[] {sender, e});
                return;
            }

            this.progressBar.Value = 0;
            
            if (this.testRunner.ErrorsOccured)
            {
                this.UpdateStatus(Resource.StatusBarLabelTestCompletedFailure);
            }
            else
            {
                this.UpdateStatus(Resource.StatusBarLabelTestCompletedSuccess);
            }
        }

        /// <summary>
        /// Handles the ExecutionStarted event of the testRunner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestRunnerExecutionStarted(object sender, EventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler(TestRunnerExecutionStarted), new object[] { sender, e });
                return;
            }

            this.resultsLabel.Visible = false;
            this.UpdateStatus(Resource.StatusBarLabelTestExecuting);
        }

        /// <summary>
        /// Handles the Progress event of the testRunner control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="Wax.TestProgressEventArgs"/> instance containing the event data.</param>
        private void TestRunnerProgress(object sender, TestProgressEventArgs e)
        {
            if (this.InvokeRequired)
            {
                this.Invoke(new EventHandler<TestProgressEventArgs>(TestRunnerProgress), new object[] { sender, e });
                return;
            }

            this.progressBar.Value = e.PercentComplete;
        }

        #endregion

        #region Toolstrip event handlers

        /// <summary>
        /// Handles the tool strip Click event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void ToolStripOnClick(object sender, EventArgs e)
        {
            if (sender == this.playButton)
            {
                TestRunnerBeginStart();
            } else if (sender == this.refreshButton)
            {
                RefeshTestScriptFile();
            }
        }        

        #endregion

        #region Menu event handlers

        /// <summary>
        /// Handles the OnClick event of the FileMenu control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void FileMenuOnClick(object sender, EventArgs e)
        {
            if (sender == this.exitToolStripMenuItem)
            {
                this.Close();
            }
            else if (sender == this.openToolStripMenuItem)
            {
                this.OpenTestScriptFile();
            }
        }


        /// <summary>
        /// Handles the OnClick event of the TestMenu control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestMenuOnClick(object sender, EventArgs e)
        {
            if (sender == this.executeToolStripMenuItem)
            {
                this.TestRunnerBeginStart();
            } 
            else if (sender == this.refreshToolStripMenuItem)
            {
                this.RefeshTestScriptFile();
            }
        }

        /// <summary>
        /// Handles the OnClick event of the HelpMenu control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void HelpMenuOnClick(object sender, EventArgs e)
        {
            if (sender == this.aboutWaxRunnerToolStripMenuItem)
            {
                AboutWaxRunner aboutForm = new AboutWaxRunner();
                aboutForm.ShowDialog(this);
            }
        }

        #endregion

        #region Open file methods

        /// <summary>
        /// Opens the test script file.
        /// </summary>
        private void OpenTestScriptFile()
        {
            if (openFileDialog.ShowDialog() == DialogResult.OK)
            {
                try
                {
                    testRunner.FileName = openFileDialog.FileName;
                    TestRunnerLoad();
                }
                catch (FileNotFoundException)
                {
                    DisplayErrorMessage(Resource.MainFormFileNotFound);
                }
                catch (ArgumentException)
                {
                    DisplayErrorMessage(Resource.MainFormFileFormatNotSupported);
                }
                catch (ParseException parseException)
                {
                    DisplayErrorMessage(parseException.Message);
                }
            }

        }

        /// <summary>
        /// Refeshes the test script file.
        /// </summary>
        private void RefeshTestScriptFile()
        {
            this.TestRunnerLoad();
            this.UpdateStatus(Resource.StatusBarLabelTestScriptRefreshed);
        }

        #endregion

        #region Error handling methods

        private void DisplayErrorMessage(string message)
        {
            MessageBox.Show(string.Format(CultureInfo.InvariantCulture, message, openFileDialog.FileName), Resource.ErrorDialogTitle, MessageBoxButtons.OK);
        }

        #endregion

        #region TestGrid event handlers

        /// <summary>
        /// Handles the grid item selected event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TestGridItemSelected(object sender, EventArgs e)
        {
            Command command = sender as Command;
            Test test = sender as Test;

            if (command != null)
            {
                this.resultsPanel.DisplayCommandItem(command);
            }
            else if (test != null)
            {
                this.resultsPanel.DisplayTestItem(test);
            }
        }

        #endregion

        #region TestRunner methods

        /// <summary>
        /// Handles loading the Test runner.
        /// </summary>
        private void TestRunnerLoad()
        {
            this.testRunner.Load();
            this.playButton.Enabled = true;
            this.refreshButton.Enabled = true;
            this.executeToolStripMenuItem.Enabled = true;
            this.refreshToolStripMenuItem.Enabled = true;
        }

        /// <summary>
        /// Tests the runner begin start.
        /// </summary>
        private void TestRunnerBeginStart()
        {
            Thread thread = new Thread(new ThreadStart(this.TestRunnerStart));
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
        }

        /// <summary>
        /// Handles starting of the test runner.
        /// </summary>
        private void TestRunnerStart()
        {
            this.testRunner.Execute();
        }

        #endregion

        #endregion
    }
}
